package edu.stthomas.seis752.service;

import java.io.File;
import java.nio.ByteBuffer;
import java.util.Date;
import java.util.List;

import javax.servlet.ServletContext;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import edu.stthomas.seis752.dao.MediaDao;
import edu.stthomas.seis752.model.Media;
import edu.stthomas.seis752.model.MediaType;
import edu.stthomas.seis752.model.User;

import org.springframework.web.multipart.MultipartFile;

import com.google.appengine.api.files.AppEngineFile;
import com.google.appengine.api.files.FileService;
import com.google.appengine.api.files.FileServiceFactory;
import com.google.appengine.api.files.FileWriteChannel;
import com.google.appengine.api.files.GSFileOptions.GSFileOptionsBuilder;

@Service
public class MediaServiceImpl implements MediaService {

	@Autowired
	private MediaDao mediaDao;
	
	@Value("${com.google.cloud.storage.bucket.name}")
	private String BUCKET_NAME;
    @Value("${com.google.cloud.storage.acl}")
    private String ACL;
    @Value("${com.google.cloud.storage.resourceUrl}")
    private String storageResourceUrl;
    @Value("${jibster.running.onAppEngine}")
    private boolean runningOnAppEngine;
    
    @Autowired
    private ServletContext servletContext;
    
    private static final Logger logger = LoggerFactory.getLogger(MediaServiceImpl.class);

	@Override
	public List<Media> getUserMedia(long userId) {
	    List<Media> mediaList = mediaDao.getUserMedia(userId);
	    return mediaList;
	}

	@Override
	@Transactional
	public void addMedia(Media media) {
		// TODO Auto-generated method stub
		mediaDao.addMedia(media);

	}
	
	@Override
	@Transactional
	public Media uploadMedia(MultipartFile multipartFile, User owner, String mediaName){
	    String fileUrl = null;
	    Media media = null;
	    if(runningOnAppEngine){
	        fileUrl = uploadToAppEngine(multipartFile);
	    }
	    else {
	        fileUrl = uploadLocally(multipartFile);
	    }
	    if(fileUrl != null){
            String fileName = multipartFile.getOriginalFilename();
            String mimeType = multipartFile.getContentType();
            MediaType mediaType = new MediaType();
            if(mimeType.contains("image")){
                mediaType.setCode("PIC");
            }
            else if(mimeType.contains("video") || mimeType.contains("octet-stream")|| mimeType.contains("ogg")){
                mediaType.setCode("VID");
            }
            // we dont know what this format is. will determine with the team, if this needs to be validation error or we just save in database as uknnown
            else {
                mediaType.setCode("UNK");
            }
            media = new Media();
            media.setMediaType(mediaType);
            media.setFileName(fileName);
            media.setUser(owner);
            media.setName(mediaName);
            media.setFileLocation(fileUrl);
            Date now = new Date();
            media.setCreateDate(now);
            
            // persist the media
            addMedia(media);
	    }
	    return media;
	}
	
	
	private String uploadToAppEngine(MultipartFile multipartFile){
	    String fileUrl = null;
        String fileName = multipartFile.getOriginalFilename();
        String mimeType = multipartFile.getContentType();
	    try{
            FileService fileService = FileServiceFactory.getFileService();
            GSFileOptionsBuilder optionsBuilder = new GSFileOptionsBuilder()
                    .setBucket(BUCKET_NAME)
                    .setKey(fileName)
                    .setMimeType(mimeType)
                    .setAcl(ACL);
            AppEngineFile writableFile = fileService.createNewGSFile(optionsBuilder.build());
            // Open a channel to write to it
            boolean lock = true;
            FileWriteChannel writeChannel = fileService.openWriteChannel(writableFile, lock);
            writeChannel.write(ByteBuffer.wrap(multipartFile.getBytes()));
            // After below line, the file is visible in App Engine as: (http://storage.googleapis.com/BUCKET_NAME/fileName)
            writeChannel.closeFinally();
	    } catch (Exception e) {
	        logger.error(e.getMessage());
	        return fileUrl;
        }
        // add the file URL:
        fileUrl = storageResourceUrl + "/" + BUCKET_NAME + "/" + fileName;
	    return fileUrl;
	}
	
	public String uploadLocally(MultipartFile multipartFile){
	    String fileUrl = null;
	    String saveDirectory = servletContext.getRealPath("/resources/upload") + "/";
	    String localResourcesURL = servletContext.getContextPath() + "/resources/upload/";
	    String fileName = multipartFile.getOriginalFilename();
	    try{
	        //save the file under servletContext().getRealPath("/resources/upload") + "/"
	        multipartFile.transferTo(new File(saveDirectory + fileName ) );
	    } catch(Exception e){
	        // if we got an exception return fileUrl which will be null so the caller knows operation didn't succeed
	        logger.error(e.getMessage());
	        return fileUrl;
	    }
	        
        // This will be the URL that we need to save to Media record as location of file
        fileUrl = localResourcesURL +  fileName;
        return fileUrl;
	}

}